package cn.newgrand.netcall.personal.contact.entity;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.util.log.Log;

import cn.newgrand.netcall.personal.contact.PersonalContactDef;

/**
 * @author SidneyRen E-mail:SidneyRen@hotmail.com
 * @version create time：2010-10-11 下午05:06:47
 * 
 *          netcall客户端增加常用联系人、自定义组、常用部门、最近联系人功能的实体类， 主要用于持久化
 *          以上几个功能的配置信息。保存于本地、远程的xml形式。
 * 
 *          xml格式：
 * 
 *          <personalContact>
 *          常用联系人：<frequentContacts><user><jid></jid><nickName></nickName></user></frequentContacts>
 *          自定义组：<personalGroups><group><name></name><members><jid></jid></members></group></customizedGroups>
 *          常用部门：<frequentDepts><dept><name></name></dept></frequentDepts>
 *          最近联系人：<recentContacts><jid></jid></recentContacts>
 *          </personalContact>
 */	
public class PersonalContact {
	// jid
	private Collection<FrequentContact> frequentContacts = new HashSet<FrequentContact>();
	private Map<String,PersonalGroup> personalGroups = new HashMap<String,PersonalGroup>();
	private Collection<String> frequentDepts = new HashSet<String>();
	private Collection<String> recentContacts = new HashSet<String>();
	private static PersonalContact instance;
	private static final Object LOCK = new Object();
	
//	public static PersonalContact getInstance(){
//		synchronized (LOCK) {
//			if(null==instance){
//				instance = new PersonalContact();
//				return instance;
//			}else{
//				return instance;
//			}
//		}
//	}
	
	/**
	 * 
	 */
	public PersonalContact() {
		
	}
	
	/**
	 * 初始化装载配置信息
	 * 
	 */
	public void init(){
		try {
			loadPersistedSetting();
		} catch (FileNotFoundException e) {
			Log.error("personal_contact_setting.xml is not exist"+e.getMessage());
		} catch (DocumentException e) {
			Log.error("read personal_contact_setting.xml error"+e.getMessage());
		}
	}

	private PersonalContact(Collection<FrequentContact> frequentContacts,
			Map<String,PersonalGroup> personalGroups,
			Collection<String> frequentDepts, Collection<String> recentContacts) {
		super();
		this.frequentContacts = frequentContacts;
		this.personalGroups = personalGroups;
		this.frequentDepts = frequentDepts;
		this.recentContacts = recentContacts;
	}

	public Collection<FrequentContact> getFrequentContacts() {
		return frequentContacts;
	}

	public void setFrequentContacts(Collection<FrequentContact> frequentContacts) {
		this.frequentContacts = frequentContacts;
	}

	public Map<String,PersonalGroup> getPersonalGroups() {
		return personalGroups;
	}

	public void setPersonalGroups(Map<String,PersonalGroup> personalGroups) {
		this.personalGroups = personalGroups;
	}

	public Collection<String> getFrequentDepts() {
		return frequentDepts;
	}

	public void setFrequentDepts(Collection<String> frequentDepts) {
		this.frequentDepts = frequentDepts;
	}

	public Collection<String> getRecentContacts() {
		return recentContacts;
	}

	public void setRecentContacts(Collection<String> recentContacts) {
		this.recentContacts = recentContacts;
	}
	
	public boolean hasContent() {
		return frequentContacts.size() > 0 || frequentDepts.size() > 0
				|| personalGroups.size() > 0;
	}

	public boolean hasFrequentContactsContent() {
		return frequentContacts.size() > 0;
	}

	public boolean hasFrequentDeptsContent() {
		return frequentDepts.size() > 0;
	}

	public boolean hasPersonalGroupsContent() {
		return personalGroups.size() > 0;
	}
	
	public String getChildElementXML() {
		StringBuilder sb = new StringBuilder();
		new PersonalContactWriter(sb).write();
		return sb.toString();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (null == obj || !getClass().isInstance(obj))
			return false;

		final PersonalContact pg = (PersonalContact) obj;

		if (!frequentContacts.equals(pg.frequentContacts)) {
			return false;
		}
		if (!frequentDepts.equals(pg.frequentDepts)) {
			return false;
		}
		if (!personalGroups.equals(pg.personalGroups)) {
			return false;
		}
		return true;
	}

	@Override
	public int hashCode() {
		int result;
		result = personalGroups.hashCode();
		result = 29 * result + frequentContacts.hashCode();
		result = 29 * result + frequentDepts.hashCode();
		return result;
	}
	
	private class PersonalContactWriter {

        private final StringBuilder sb;

        PersonalContactWriter(StringBuilder sb) {
            this.sb = sb;
        }

        public void write() {
            appendTag(PersonalContactDef.XML_PERSONAL_CONTACT_HEAD_TAG, hasContent(), new ContentBuilder() {
                public void addTagContent() {
                    buildActualContent();
                }
            });
        }

        private void buildActualContent() {
        	if (hasFrequentContactsContent()) {
        		appendFrequentContacts(frequentContacts);
        	}
        	if (hasFrequentDeptsContent()) {
        		appendFrequentDepts(frequentDepts);
        	}
            if (hasPersonalGroupsContent()) {
            	appendPersonalGroups(personalGroups);
            }
            
        }

        private void appendFrequentContacts(final Collection<FrequentContact> fc) {
        	if (fc.size() > 0) {
        		appendTag(PersonalContactDef.XML_FREQUENT_CONTACTS_TAG, true, new ContentBuilder() {
		        	public void addTagContent() {
		        		final Iterator it = fc.iterator();
		        				while (it.hasNext()) {
		        					final FrequentContact entity = (FrequentContact) it.next();
		        					appendTag(PersonalContactDef.XML_USER_TAG, true, new ContentBuilder() {
				        				public void addTagContent(){
		        					appendTag(PersonalContactDef.XML_USER_JID_TAG, StringUtils.escapeForXML((String) entity.getJid()));
		        					appendTag(PersonalContactDef.XML_USER_NICKNAME_TAG, StringUtils.escapeForXML((String) entity.getNickName()));
				        		}});
				        }
		            }});
        		}
        }
        
        private void appendFrequentDepts(final Collection<String> fd) {
        	if (fd.size() > 0) {
        		appendTag(PersonalContactDef.XML_FREQUENT_DEPTS_TAG, true, new ContentBuilder() {
        			public void addTagContent(){
        				
                				Iterator it = fd.iterator();
                				while (it.hasNext()) {
                					final String entity = (String) it.next();
                					appendTag(PersonalContactDef.XML_DEPT_TAG, true, new ContentBuilder() {
                    					public void addTagContent() {
                					appendTag(PersonalContactDef.XML_DEPT_NAME_TAG, StringUtils.escapeForXML(entity));
                    					}});
                				}
        			
        			}
        		});
        	}
        }
        private void appendPersonalGroups(final Map<String,PersonalGroup> pgMap) {
            if (pgMap.size() > 0) {
                appendTag(PersonalContactDef.XML_PERSONAL_GROUPS_TAG, true, new ContentBuilder() {
                	public void addTagContent() {
                		appendTag(PersonalContactDef.XML_GROUP_TAG, true, new ContentBuilder() {
	                	  public void addTagContent() {
	                    	for(final PersonalGroup entity : pgMap.values()){
	                            appendTag(PersonalContactDef.XML_GROUP_NAME_TAG, StringUtils.escapeForXML((String) entity.getName()));
	                            
	                            if(entity.getMembers().size()>0)
		                            appendTag(PersonalContactDef.XML_GROUP_MEMBERS_TAG, true, new ContentBuilder() {
			                           public void addTagContent(){
		                            	for(String m : entity.getMembers())
			                            appendTag(PersonalContactDef.XML_USER_JID_TAG, StringUtils.escapeForXML(m));
	                            }});
	                        }
	                    }
                });
            }
        });}
        }

        private void appendEmptyTag(Object tag) {
            sb.append('<').append(tag).append("/>");
        }
        
//        private void appendFrequentContacts() {
//            appendTag("frequentContacts", true, new ContentBuilder() {
//                public void addTagContent() {
//                	
//                    appendTag("jid", StringUtils.escapeForXML(lastName));
//                    appendTag("nickName", StringUtils.escapeForXML(firstName));
//                }
//            });
//        }

        private void appendTag(String tag, String attr, String attrValue, boolean hasContent,
                ContentBuilder builder) {
            sb.append('<').append(tag);
            if (attr != null) {
                sb.append(' ').append(attr).append('=').append('\'').append(attrValue).append('\'');
            }

            if (hasContent) {
                sb.append('>');
                builder.addTagContent();
                sb.append("</").append(tag).append(">\n");
            }
            else {
                sb.append("/>\n");
            }
        }

        private void appendTag(String tag, boolean hasContent, ContentBuilder builder) {
            appendTag(tag, null, null, hasContent, builder);
        }

        private void appendTag(String tag, final String tagText) {
            if (tagText == null) return;
            final ContentBuilder contentBuilder = new ContentBuilder() {
                public void addTagContent() {
                    sb.append(tagText.trim());
                }
            };
            appendTag(tag, true, contentBuilder);
        }

    }
	
	/**
	 * 解析加载personal_contact_setting.xml文件
	 * @throws DocumentException 
	 * @throws FileNotFoundException 
	 */
	public void loadPersistedSetting() throws FileNotFoundException, DocumentException{
		
		File file = getPersonalContactFile();
		if(!file.exists())return ;
		SAXReader saxReader = new SAXReader();
		saxReader.setEncoding("UTF-8");
		Document document = saxReader.read(new FileReader(file));
		loadPersistedSetting(document);
		
	}
	public void loadPersistedSetting(Document document){
		if(null==document) return ;
		if(!document.hasContent())return;
		
		try {
			loadFrequentContacts(document);
		} catch (Exception e) {
			frequentContacts.clear();
//			Log.error("load frequent contacts error:"+e.getMessage());
		}
		try {
			loadFrequentDepts(document);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			frequentDepts.clear();
//			Log.error("load frequent depts error:"+e.getMessage());
		}
		try {
			loadPersonalGroups(document);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			personalGroups.clear();
//			Log.error("load personal groups error:"+e.getMessage());
		}
	}
	public void loadFrequentContacts(Document document) throws Exception{
		if(null==document) return ;
		if(!document.hasContent())return;
		Element personalContact = document.getRootElement();
		Element frequentContacts = personalContact.element(PersonalContactDef.XML_FREQUENT_CONTACTS_TAG);
		if(null==frequentContacts) return;
		Iterator<Element> userIter = frequentContacts.elementIterator(PersonalContactDef.XML_USER_TAG);
		Collection<FrequentContact> fcs = new HashSet<FrequentContact>();
		while(userIter.hasNext()){
			FrequentContact fcTemp = new FrequentContact();
			Element user = userIter.next();
			String jid = null;
			String nickName = null;
			Iterator<Element> userElements = user.elementIterator();
			while(userElements.hasNext()){
				Element userElement = userElements.next();
				String nameElement = userElement.getName();
				if (PersonalContactDef.XML_USER_JID_TAG.equals(nameElement)) {
					jid = userElement.getText();
					fcTemp.setJid(jid);
				} else if (PersonalContactDef.XML_USER_NICKNAME_TAG.equals(nameElement)) {
					nickName = userElement.getText();
					fcTemp.setNickName(nickName);
				} 
			}
			fcs.add(fcTemp);
		}
		setFrequentContacts(fcs);
	}
	public void loadFrequentDepts(Document document)throws Exception{
		if(null==document) return ;
		if(!document.hasContent())return;
		Element personalContact = document.getRootElement();
		Element frequentDepts = personalContact.element(PersonalContactDef.XML_FREQUENT_DEPTS_TAG);
		if(null==frequentDepts) return;
		Iterator<Element> userIter = frequentDepts.elementIterator(PersonalContactDef.XML_DEPT_TAG);
		Collection<String> fds = new HashSet<String>();
		while(userIter.hasNext()){
			String fdTemp = null;
			Element user = userIter.next();
			Iterator<Element> userElements = user.elementIterator();
			while(userElements.hasNext()){
				Element userElement = userElements.next();
				String nameElement = userElement.getName();
				if (PersonalContactDef.XML_DEPT_NAME_TAG.equals(nameElement)) {
					fdTemp = userElement.getText();
				}
				fds.add(fdTemp);
			}
			setFrequentDepts(fds);
		}
	}
	public void loadPersonalGroups(Document document)throws Exception{
		if(null==document) return ;
		if(!document.hasContent())return;
		Element personalContact = document.getRootElement();
		Element personalGroups = personalContact.element(PersonalContactDef.XML_PERSONAL_GROUPS_TAG);
		if(null==personalGroups) return;
		Iterator<Element> groupIter = personalGroups.elementIterator(PersonalContactDef.XML_GROUP_TAG);
		Map<String,PersonalGroup> pgs = new HashMap<String,PersonalGroup>();
		while(groupIter.hasNext()){
			PersonalGroup pgTemp = new PersonalGroup();
			Element user = groupIter.next();
			String jid = null;
			String name = null;
			Iterator<Element> groupElements = user.elementIterator();
			
			while(groupElements.hasNext()){
				Element groupElement = groupElements.next();
				String nameElement = groupElement.getName();
				if (PersonalContactDef.XML_GROUP_NAME_TAG.equals(nameElement)) {
					name = groupElement.getText();
					pgTemp.setName(name);
				} else if (PersonalContactDef.XML_GROUP_MEMBERS_TAG.equals(nameElement)) {
					Iterator<Element> membersElements = groupElement.elementIterator();
					Collection<String> members = new HashSet<String>();
					while(membersElements.hasNext()){
						Element memberElement = membersElements.next();
						if(PersonalContactDef.XML_USER_JID_TAG.equals(memberElement.getName())){
							jid = memberElement.getText();
						}
						members.add(jid);
					}
					pgTemp.setMembers(members);
				} 
			}
			pgs.put(pgTemp.getName(),pgTemp);
		}
		setPersonalGroups(pgs);
	}
	
	/**
     * Returns the settings file.
     *
     * @param jid the
     * @return the settings file.
     */
    public static File getPersonalContactFile() {
//    	return new File(SparkManager.getUserDirectory(), "personal_contact_setting.xml");
        return new File("D:\\", "personal_contact_setting.xml");
        
    }

    //==============================================================

    private interface ContentBuilder {

        void addTagContent();
    }

    //==============================================================

}
